/* GNU Mailutils -- a suite of utilities for electronic mail
   Copyright (C) 1999, 2000, 2001, 2005, 2007 Free Software Foundation, Inc.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 3 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General
   Public License along with this library; if not, write to the
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301 USA */


/**
 * \file invariants_collector.cc
 * \author Ice and Magic
 * \date 21 Avril 2011
 * 
 */



#include <iostream>
#include "silhouette.h"
#include "invariants_collector.h"
#include "constants.h"
#include "global.h"

using namespace std;

#ifdef MY_GO_PARALLEL
#ifdef USE_TBB
#include "tbb/task.h"
using namespace tbb;
class	ClimbTask : public task{
public:
	set<__type>*	id;
	__type		nb;
	Silhouette	s;
	int		l;
	int		r;
	int		d;

ClimbTask(set<__type>* __id, __type __nb, Silhouette __s, int __l, int __r, int __d)
	:id(__id), nb(__nb),s(__s),l(__l),r(__r),d(__d) 
{
/*		id=__id;
		nb=__nb;
		s=__s;
		l=__l;
		r=__r;
		d=__d;*/
		}

~ClimbTask(){
}


task*	execute(){

//	if(r == 0)
//		return NULL;

	if(d-r < 1 && r > 0  && d>=12){	// si je suis en haut de la récursion *
					// et assez de job => go parallel	
					

		ClimbTask*	task_array[l];
		set<__type>	results[l];
		volatile	int i;

		set_ref_count(l);
		for(i=1;i<this->l;i++){
			Silhouette si=s;
			si.digit_occurrences[i]++;
			ClimbTask&	task  = *new (allocate_child()) ClimbTask(&(results[i]), nb*10+i,si,i+1,r-1,d);

			if(i<l-1)
				spawn(task);
			else
				spawn_and_wait_for_all(task);

			}

		for(int i=1;i<this->l;i++){
			id->insert(results[i].begin(), results[i].end());
			}
		return NULL;
		}
	else{

#ifdef FULL_VERBOSE
cout<<"\nDEBUG TASK::EXECUTE SEQ\n";
#endif

		set<__type>	res;

		res=generateur_silhouettes(
					#ifdef FULL_VERBOSE
					nb,
					#endif
					s,l,r,d);
		id->insert(res.begin(),res.end());

		return NULL;
		}

	return NULL;
	}

};

class ClimbTask;

#undef USE_OMP
#endif // USE_TBB


#ifdef USE_OMP
#include <omp.h>
#endif	// USE_OMP
#endif	// MY_GO_PARALLEL



///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////

void	
i_collector::collect(){

#ifdef MY_GO_PARALLEL
#ifdef USE_OMP
int depth=weight(m_ub)+1;
Silhouette s(0);
set<__type>	results[__DIGITS];

//omp_set_num_threads(9);
#pragma omp parallel for\
	default(none) \
	firstprivate(s,depth) \
	shared(results)\
	schedule(dynamic)
for(int i=1;i<__DIGITS;i++){
		Silhouette si=s;
		si.digit_occurrences[i]++;
		results[i]=  generateur_silhouettes(
				#ifdef FULL_VERBOSE
				0,
				#endif
				si,i+1,depth-1,depth);
		}

// Collect des tous les points fixes des fils
for(int i=1;i<__DIGITS;i++)
	invariants.insert(results[i].begin(),results[i].end());

return;
#endif	//OMP


#ifdef USE_TBB
int depth=weight(m_ub)+1;
Silhouette s(0);
set<__type>	results[__DIGITS];

ClimbTask& t = *new (task::allocate_root ()) ClimbTask (
		&(this->invariants),
//		#ifdef FULL_VERBOSE
//		0,
//		#else	
		0,
//		#endif
		s,__DIGITS,depth,depth);

task::spawn_root_and_wait(t);

return;

#endif // USE_TBB

#endif // GO_PARALLEL

#ifndef MY_GO_PARALLEL
int depth=weight(m_ub)+1;
Silhouette s(0);
set<__type>	results[__DIGITS];


// la version non parallel
invariants=generateur_silhouettes(
		#ifdef FULL_VERBOSE
		0,
		#endif
		s,__DIGITS,depth,depth);
return;
#endif
}

///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
std::ostream&	operator<<(std::ostream& out, const i_collector& c){
	int i=1;
for(std::set<__type>::iterator it=c.invariants.begin(); it != c.invariants.end(); it++)
	if(*it >= c.m_lb && *it <=c.m_ub)
		out<<"\n"<<i<<" "<<*it,i++;
return out;
}

///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////

